﻿
using System;
using System.IO;
using System.Net.Sockets;

namespace MX.Core.Caching.Redis.Sider.Executors
{
	// TODO: Filter invalid commands
	internal abstract class ExecutorBase : IExecutor
	{
		public RedisClientBase Client { get; private set; }

		public abstract Mode Mode { get; }

    
		protected ProtocolReader Reader { get { return Client.Reader; } }

		protected ProtocolWriter Writer { get { return Client.Writer; } }


		public virtual void Init (RedisClientBase client)
		{
			SAssert.ArgumentNotNull (() => client);
			Client = client;
		}

		public virtual void Init (IExecutor previous)
		{
			SAssert.ArgumentNotNull (() => previous);
			Client = previous.Client;
		}


		public abstract T Execute<T> (Invocation<T>  invocation,Stream stream);


		protected T ExecuteImmediate<T> (Invocation<T>  invocation,Stream stream)
		{
			invocation.WriteAction (Writer, stream);
			Writer.Flush (stream);

			var result = invocation.ReadAction (Reader, stream);

			// handle connection state changes after some commands
			if (invocation.Command == "QUIT" ||
			    invocation.Command == "SHUTDOWN")
				Client.Dispose ();

			return result;
		}


		 

		protected bool HandleTimeout (Exception ex)
		{
			// assumes Redis disconnected (thus the IOException/SocketException)
			// due to idle timeout.
			if (!(ex is IOException || ex is ObjectDisposedException ||
			    ex is SocketException))
				return false;

			Client.Dispose ();
			 
			throw new IdleTimeoutException (ex);

			// reconnect client
			//Client.Reset ();
			 
		}


		public virtual void Dispose ()
		{
		}
	}
}
